@file:Suppress("unused")

package xyz.liut.ee.req

import jakarta.servlet.ServletException
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import xyz.liut.ee.web.toJsonString
import xyz.liut.logcat.L
import xyz.liut.logcat.kt.logDebug
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.lang.reflect.Array
import java.nio.charset.StandardCharsets
import java.util.*


/**
 * 打印请求
 *
 * @param req  请求
 * @param resp 回应
 * @throws IOException -
 */
@Throws(IOException::class)
fun printReqReflect(req: HttpServletRequest?, resp: HttpServletResponse) {
    val reqInfo = getReqReflectInfo(req)
    L.d(reqInfo)
    resp.writer.println(reqInfo)
}

/**
 * 请求参数
 *
 * @param req 请求
 */
fun getReqReflectInfo(req: HttpServletRequest?): String {
    val builder = StringBuilder("---------------------------------\n")
    for (method in HttpServletRequest::class.java.methods) {
        if (method.name.startsWith("get") && method.parameterCount == 0 && !method.name.equals(
                "getInputStream",
                ignoreCase = true
            )
        ) {
            builder.append(method.name.replace("get", "")).append(":  ")
            try {
                val obj = method.invoke(req)
                when {
                    obj == null -> {
                        builder.append("NONE").append("\n")
                    }

                    obj.javaClass.name.startsWith("[") -> {
                        val length = Array.getLength(obj)
                        builder.append("[")
                        for (i in 0 until length) {
                            val item = Array.get(obj, i)
                            builder.append(item)
                            if (i != length - 1) {
                                builder.append(", ")
                            }
                        }
                        builder.append("]").append("\n")
                    }

                    else -> {
                        builder.append(obj).append("\n")
                    }
                }
            } catch (ignored: Exception) {
            }
        }
    }
    return builder.append("---------------------------------\n").toString()
}

/**
 * 打印请求
 *
 * @param req 请求
 */
@Throws(IOException::class, ServletException::class)
fun HttpServletRequest.printReq() {
    logDebug { getSimpleReqInfo().toJsonString() }
}

/**
 * 请求参数
 */
@Throws(IOException::class, ServletException::class)
fun HttpServletRequest.getSimpleReqInfo(): ReqBean {

    val reqBean = ReqBean()
    reqBean.RequestURL = requestURL.toString()
    reqBean.Method = method
    reqBean.Protocol = protocol
    reqBean.ServerPort = serverPort.toString()
    reqBean.QueryString = queryString

    // TODO auth 相关
    reqBean.authType = authType
    reqBean.remoteUser = remoteUser
    reqBean.userPrincipal = userPrincipal?.toString()


    // header
    val headers = mutableMapOf<String, String>()
    reqBean.headers = headers
    val headerNames = this.headerNames
    while (headerNames.hasMoreElements()) {
        val header = headerNames.nextElement()
        headers[header] = getHeader(header)
    }

    // body
    if (contentType?.contains("charset") == true ||
        contentType?.contains("json") == true ||
        contentType?.contains("x-www-form-urlencoded") == true ||
        contentType?.contains("text") == true
    ) {
        inputStream.use { reqBean.body = String(it.readBytes()) }
    }

    // multipart
    else if (contentType?.contains("multipart") == true) {
        // parts
        val partBeans = mutableListOf<ReqBean.PartBean>()
        reqBean.parts = partBeans
        val parts = this.parts
        try {
            if (parts != null) {
                for (part in parts) {
                    val partBean = ReqBean.PartBean()
                    partBeans.add(partBean)
                    partBean.Name = part.name
                    partBean.ContentType = part.contentType
                    partBean.SubmittedFileName = part.submittedFileName
                    partBean.Size = part.size.toString()

                    val partHeaders = mutableMapOf<String, String>()
                    val partHeaderNames = part.headerNames
                    for (partHeaderName in partHeaderNames) {
                        partHeaders[partHeaderName] = part.getHeader(partHeaderName)
                    }
                }
            }
        } catch (ignored: Throwable) {
            ignored.printStackTrace()
        }

    }

    // 其它数据格式
    else if (contentLength > 0) {
        val body = inputStream.readBytes()
        val base64Body = Base64.getEncoder().encode(body)
        reqBean.body = String(base64Body)
    }

    return reqBean
}

/**
 * 打印请求
 *
 * @param req  请求
 * @param resp 回应
 * @throws IOException -
 */
@Throws(IOException::class, ServletException::class)
fun printRawBody(req: HttpServletRequest, resp: HttpServletResponse) {
    val reqInfo = getRawReqBody(req)
    L.d(reqInfo)
    resp.contentType = "text/html;charset=UTF-8"
    resp.writer.println(reqInfo)
}

/**
 * 请求参数
 *
 * @param req 请求
 */
fun getRawReqBody(req: HttpServletRequest): String {
    val builder = StringBuilder("-------------RawReqBody-------------\n\n")
    try {
        val reader = BufferedReader(InputStreamReader(req.inputStream, StandardCharsets.UTF_8))
        reader.lines().forEach { s: String? -> builder.append(s).append("\n") }
        reader.close()
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return builder.append("\n-------------RawReqBody-------------\n").toString()
}
